package com.xb.chain.utils;

import com.xb.chain.block.AbstractBlockChain;
import com.xb.chain.entity.Block;
import com.xb.chain.entity.Result;
import com.xb.chain.pow.ProofOfWork;

import java.util.Collections;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author xiaobin
 * @date 2020/3/18 22:23
 * @desc
 */
public interface BlockUtils {

    public static Result compareBlockChain(CopyOnWriteArrayList<Block> nodeList, CopyOnWriteArrayList<Block> otherList) {
        CopyOnWriteArrayList<Block> addBlockList = new CopyOnWriteArrayList<Block>();

        // 本节点（本机节点），同节点（同步节点）
        // 获取本节点最后一个，然后去同节点查找，查找到将同节点之后得节点加上，验证是否正确
        Block block = nodeList.get(nodeList.size() - 1);
        for (int i = otherList.size() - 1; i >= 0; i--) {
            Block otherBlock = otherList.get(i);
            if (otherBlock.getBlockHash().equals(block.getBlockHash())) {
                // 假如大小都不合适，说明链有问题，不同步
                if ((nodeList.size() - 1) == i) {
                    CopyOnWriteArrayList<Block> tempList = new CopyOnWriteArrayList<Block>();
                    tempList.addAll(addBlockList);
                    return validateBlockChain(tempList);
                } else {
                    return Result.error("同步链存在问题，停止同步");
                }
            } else {
                addBlockList.add(otherBlock);
            }
        }
        return Result.error("同步链和本节点链不一致");
    }


    public static Result validateBlockChain(CopyOnWriteArrayList<Block> list) {
        for (int i = list.size() - 1; i > 0; i--) {
            // 1、判断prehash是否相同
            // 2、判断时间戳
            // 3、验证数据
            Block block = list.get(i);
            Block preBlock = list.get(i - 1);
            if (!block.getPreviousHash().equals(preBlock.getBlockHash())) {
                return Result.error("区块hash被修改");
            } else if (block.getTime() < preBlock.getTime()) {
                return Result.error("区块hash时间被修改");
            } else if (!ProofOfWork.newPow(block).validate() || !ProofOfWork.newPow(preBlock).validate()) {
                return Result.error("区块数据被修改");
            }
        }
        return Result.ok("区块链正常");
    }

}
